package com.ruyuan.process.engine.model;

import com.ruyuan.process.engine.instance.ProcessorInstanceCreator;
import com.ruyuan.process.engine.instance.ReflectNodeInstanceCreator;
import com.ruyuan.process.engine.node.ProcessorDefinition;
import com.ruyuan.process.engine.process.ProcessContext;
import lombok.extern.slf4j.Slf4j;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author zhonghuashishan
 * @version 1.0
 */
@Slf4j
public class ProcessContextFactory {

    public static final ProcessorInstanceCreator DEFAULT_INSTANCE_CREATOR = new ReflectNodeInstanceCreator();
    private List<ProcessModel> modelList;
    private final Map<String, ProcessorDefinition> processorDefinitionMap = new ConcurrentHashMap<>();
    private final ProcessorInstanceCreator instanceCreator;

    public ProcessContextFactory(List<ProcessModel> modeList) throws Exception {
        this(modeList, DEFAULT_INSTANCE_CREATOR);
    }

    public ProcessContextFactory(List<ProcessModel> modeList, ProcessorInstanceCreator instanceCreator) throws Exception {
        this.modelList = modeList;
        this.instanceCreator = instanceCreator;
        init();
    }

    private void init() throws Exception {
        // 对我们的process流程定义的数据，去做一些检查操作
        for (ProcessModel processModel : modelList) {
            processModel.check();
        }
        // 对我们的流程定义中的各个节点对应的bean实例完成构造和注入，都是从spring容器里获取的
        for (ProcessModel processModel : modelList) {
            // ProcessModel仅仅是代表了我们的流程定义配置数据
            // 我们需要的不是这种流程定义数据，我们要的是可以执行的流程
            // ProcessorDefinition，是一个可以运行的流程，我们现在需要的是这个东西
            ProcessorDefinition processorDefinition = processModel.build(instanceCreator);
            log.info("构造流程成功：\n{}", processorDefinition.toStr());
            processorDefinitionMap.put(processorDefinition.getName(), processorDefinition);
        }
    }

    public ProcessContext getContext(String name) {
        ProcessorDefinition processorDefinition = processorDefinitionMap.get(name);
        if (processorDefinition == null) {
            throw new IllegalArgumentException("流程不存在");
        }
        return new ProcessContext(processorDefinition); // 只要你一次流程实例运行
        // 把ProcessorDefinition实际可执行的流程给了他，此时在运行过程中，这套流程是不会变化的，这是一套对象，是不会变的
        // 就是直接运行就可以了
        // 如果流程还没开始的话，完成了新流程定义的解析，此时在map里拿到的就是新的一套流程定义对象
        // 按照新流程定义去运行，一边运行流程，一边刷新流程定义是没问题的
    }

    public void refresh(List<ProcessModel> modeList) throws Exception {
        synchronized (this) { // 加锁，为什么要加锁，一会儿来给大家来讲解
            this.modelList = modeList;
            init();
        }
    }

}
